﻿using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using Npgsql;
using NpgsqlTypes;
using DTO.Clases;

namespace DataAccessLayer.Clases
{
    /// <summary>
    /// Representa una clase de transferencia a Base de Datos PostgreSQL de un Producto.
    /// </summary>
    public class DaoProducto
    {
        #region Atributos

        #region Tranzacion a Base de Datos

        /// <summary>
        /// Objeto conexion a base de datos PostgreSQL.
        /// </summary>
        private Conexion conexion;

        /// <summary>
        /// Objeto que ejecuta las sentencias o procedimientos en la base de datos
        /// </summary>
        private NpgsqlCommand comando;

        /// <summary>
        /// Objeto que representa un adaptador de comandos SQl.
        /// </summary>
        private NpgsqlDataAdapter miAdapter;

        /// <summary>
        /// Objeto de Tranzacion a base de datos de Descuento.
        /// </summary>
        private DaoDescuento midaodescuento;

        /// <summary>
        /// Objeto de Tranzacion a base de datos de Recargo.
        /// </summary>
        private DaoRecargo midaorecargo;

        /// <summary>
        /// Objeto de Tranzacion a base de datos de ValorUnidadMedida
        /// </summary>
        private DaoValorUnidadMedida miDaoValor;

        /// <summary>
        /// Objeto de tranzacion a base de datos de MedidaColor.
        /// </summary>
        private DaoInventario miDaoInventario;

        #endregion

        #region Procedimientos o Funciones Almacenadas.

        /// <summary>
        /// Representa la funcion en PostgreSQL recuperar_consecutivo.
        /// </summary>
        private string sqlRecuperarConsecutivo = "recuperar_consecutivo";

        /// <summary>
        /// Representa la Funcion en PostgreSQL existe_codigo_producto.
        /// </summary>
        private string sqlComprobarCodigo = "existe_codigo_producto";

        /// <summary>
        /// Representa la Funcion en PostgreSQL existe_barra_producto.
        /// </summary>
        private string sqlComprobarBarras = "existe_barra_producto";

        /// <summary>
        /// Representa la funcion insertar_producto.
        /// </summary>
        private string SqlInsert = "insertar_producto";

        /// <summary>
        /// Representa la función ultimo_valor_producto.
        /// </summary>
        private string ultimoValor = "ultimo_valor_producto";

        /// <summary>
        /// Representa la función ultimos_valores_producto.
        /// </summary>
        private string UltimosValores = "ultimos_valores_producto";

        #endregion

        #endregion

        #region constantes

        /// <summary>
        /// Representa el texto CodigoProducto.
        /// </summary>
        private string CodigoProducto = "CodigoProducto";

        /// <summary>
        /// Representa el texto BarraProducto.
        /// </summary>
        private string BarraProducto = "BarraProducto";

        /// <summary>
        /// Representa el mensaje: Ocurrio un error al cargar la consulta.
        /// </summary>
        private string ErrorConsulta
        {
            set { ErrorConsulta = "Ocurrio un error al cargar la consulta.\n"; }
            get { return ErrorConsulta; }
        }

        /// <summary>
        /// Representa el mensaje: Ocurrio un error al cargar el total de registros.
        /// </summary>
        private string ErrorCount = "Ocurrio un error al cargar el total de registros.\n";

        /// <summary>
        /// Representa el texto: Ocurrió un error al cargar el precio del Producto.
        /// </summary>
        private string ErrorUltimoPrecio = "Ocurrió un error al cargar el precio del Producto.\n";

        #endregion

        /// <summary>
        /// Inicializa una nueva instancia de la clase DaoProducto.
        /// </summary>
        public DaoProducto()
        {
            this.conexion = new Conexion();
        }

        #region Metodos

        /// <summary>
        /// Obtiene un número disponible del Codigo Interno para registro del Producto
        /// </summary>
        /// <returns></returns>
        public int ObtenerCodigoInterno()
        {
            bool match = true;
            int codigo = 0;
            try
            {
                while (match)
                {
                    codigo = CapturarCodigoInterno();
                    if (ComprobarCodigoInterno(codigo))
                    {
                        ActualizarProductoInterno(codigo);
                        match = true;
                    }
                    else
                        match = false;
                }
                return codigo;
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al generara el codigo para el producto. " + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene un número disponible del Codigo de Barras para registro del Producto
        /// </summary>
        /// <returns></returns>
        public string ObtenerCodigoBarras()
        {
            bool match = true;
            string codigo = "";
            try
            {
                while (match)
                {
                    codigo = CapturarCodigoBarras();
                    if (ComprobarCodigoBarras(codigo))
                    {
                        ActualizarProductoBarras(codigo);
                        match = true;
                    }
                    else
                        match = false;
                }
                return codigo;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el codigo interno consecutivo del registro del Producto.
        /// </summary>
        /// <returns></returns>
        private int CapturarCodigoInterno()
        {
            try
            {
                CargarComandoStoredProcedure(sqlRecuperarConsecutivo);
                comando.Parameters.AddWithValue("concepto", CodigoProducto);
                conexion.MiConexion.Open();
                var codigo = Convert.ToInt32(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return codigo;
            }
            catch (Exception ex)
            {
                throw new Exception("No se puede generar codigo interno" + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Comprueba si el codigo existe en un registro de Producto.
        /// </summary>
        /// <param name="codigo">Codigo a comprbar.</param>
        /// <returns></returns>
        public bool ComprobarCodigoInterno(object codigo)
        {
            try
            {
                CargarComandoStoredProcedure(sqlComprobarCodigo);
                comando.Parameters.AddWithValue("codigo", Convert.ToString(codigo));
                conexion.MiConexion.Open();
                var resultado = Convert.ToBoolean(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return resultado;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                conexion.MiConexion.Close();
            }
        }

        /// <summary>
        /// Actualiza el registro consecutivo del codigo interno de producto de 1 en 1.
        /// </summary>
        /// <param name="productocodinterno">Codigo a ingresar</param>
        private void ActualizarProductoInterno(int productocodinterno)
        {
            var numero = productocodinterno + 1;
            try
            {
                CargarComandoStoredProcedure("actualizar_consecutivo");
                comando.Parameters.AddWithValue("concepto", CodigoProducto);
                comando.Parameters.AddWithValue("numero", numero.ToString());
                conexion.MiConexion.Open();
                comando.ExecuteNonQuery();
                conexion.MiConexion.Close();
                comando.Dispose();
            }
            catch (Exception ex)
            {
                throw new Exception("No se puede actualizar codigo interno. " + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene el codigo de barras consecutivo del registro del Producto.
        /// </summary>
        /// <returns></returns>
        private string CapturarCodigoBarras()
        {
            try
            {
                CargarComandoStoredProcedure("recuperar_consecutivo");
                comando.Parameters.AddWithValue("concepto", BarraProducto);
                conexion.MiConexion.Open();
                var numero = Convert.ToString(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return numero;
            }
            catch (Exception ex)
            {
                throw new Exception("No se puede generar codigo de barras. " + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Comprueba si el codigo existe en un registro de Producto.
        /// </summary>
        /// <param name="codigo">Codigo a comprbar.</param>
        /// <returns></returns>
        public bool ComprobarCodigoBarras(string codigo)
        {
            try
            {
                CargarComandoStoredProcedure(sqlComprobarBarras);
                comando.Parameters.AddWithValue("codigo", codigo);
                conexion.MiConexion.Open();
                var resultado = Convert.ToBoolean(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return resultado;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                conexion.MiConexion.Close();
            }
        }

        /// <summary>
        /// Actualiza el registro consecutivo del codigo de barras del producto de 1 en 1.
        /// </summary>
        /// <param name="productobarras">Codigo a ingresar</param>
        public void ActualizarProductoBarras(string productobarras)
        {
            var numero = Convert.ToInt64(productobarras) + 1;
            try
            {
                CargarComandoStoredProcedure("actualizar_consecutivo");
                comando.Parameters.AddWithValue("concepto", BarraProducto);
                comando.Parameters.AddWithValue("numero", numero.ToString());
                conexion.MiConexion.Open();
                comando.ExecuteNonQuery();
                conexion.MiConexion.Close();
                comando.Dispose();
            }
            catch (Exception ex)
            {
                throw new Exception("No se puede actualizar codigo barras. " + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Inserta un registro de Producto en la base de datos.
        /// </summary>
        /// <param name="producto">Producto a ingresar</param>
        public void InsertarProducto(Producto producto)
        {
            midaodescuento = new DaoDescuento();
            midaorecargo = new DaoRecargo();
            miDaoValor = new DaoValorUnidadMedida();
            miDaoInventario = new DaoInventario();
            try
            {
                CargarComandoStoredProcedure(SqlInsert);
                comando.Parameters.AddWithValue("CodigoInterno", producto.CodigoInternoProducto);
                comando.Parameters.AddWithValue("CodigoBarras", producto.CodigoBarrasProducto);
                comando.Parameters.AddWithValue("referencia", producto.ReferenciaProducto);
                comando.Parameters.AddWithValue("nombre", producto.NombreProducto);
                comando.Parameters.AddWithValue("descripcion", producto.DescripcionProducto);
                comando.Parameters.AddWithValue("categoria", producto.CodigoCategoria);
                comando.Parameters.AddWithValue("marca", producto.IdMarca);
                comando.Parameters.AddWithValue("utilidad", producto.UtilidadPorcentualProducto);
                comando.Parameters.AddWithValue("valorVenta", producto.ValorVentaProducto);
                comando.Parameters.AddWithValue("aplicaPrecio", producto.AplicaPrecioPorcentaje);
                comando.Parameters.AddWithValue("iva", producto.IdIva);
                comando.Parameters.AddWithValue("unidadVenta", producto.UnidadVentaProducto);
                comando.Parameters.AddWithValue("minima", producto.CantidadMinimaProducto);
                comando.Parameters.AddWithValue("maxima", producto.CantidadMaximaProducto);
                comando.Parameters.AddWithValue("estado", producto.EstadoProducto);
                comando.Parameters.AddWithValue("talla", producto.AplicaTalla);
                comando.Parameters.AddWithValue("color", producto.AplicaColor);
                comando.Parameters.AddWithValue("cantdecimal", producto.CantidadDecimal);
                conexion.MiConexion.Open();
                comando.ExecuteNonQuery();
                conexion.MiConexion.Close();
                comando.Dispose();

                string numero = CapturarCodigoBarras();
                if (numero == producto.CodigoBarrasProducto)
                {
                    ActualizarProductoBarras(numero);
                }
                int numero2 = CapturarCodigoInterno();
                if (numero2 == Convert.ToInt32(producto.CodigoInternoProducto))
                {
                    ActualizarProductoInterno(numero2);
                }

                /*foreach (Descuento d in producto.Descuentos)
                {
                    d.CodigoInternoProducto = producto.CodigoInternoProducto;
                    midaodescuento.InsertarDescuento(d);
                }

                foreach (Recargo r in producto.Recargos)
                {
                    r.CodigoInternoProducto = producto.CodigoInternoProducto;
                    midaorecargo.InsertarRecargo(r);
                }*/

                foreach (ValorUnidadMedida medida in producto.Medidas)
                {
                    medida.CodigoInternoProducto = producto.CodigoInternoProducto;
                    miDaoValor.InsertarMedidaProducto(medida);
                }

                foreach (Inventario inventario in producto.Inventarios)
                {
                    inventario.CodigoProducto = producto.CodigoInternoProducto;
                    miDaoInventario.InsertarInventario(inventario);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un Error al insertar Producto.\n" + ex.Message);
            }
            finally
            {
                conexion.MiConexion.Close();
            }
        }

        /// <summary>
        /// Obtiene el valor que indica si el Producto aplica talla o no.
        /// </summary>
        /// <param name="codigo">Codigo del Producto a consultar.</param>
        /// <returns></returns>
        public bool ProductoConTalla(string codigo)
        {
            try
            {
                CargarComandoStoredProcedure("producto_con_talla");
                comando.Parameters.AddWithValue("codigo", codigo);
                conexion.MiConexion.Open();
                var resultado = Convert.ToBoolean(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return resultado;
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorConsulta + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
            //producto_con_talla('525')
        }

        /// <summary>
        /// Obtiene el listado de los productos.
        /// </summary>
        /// <param name="registroBase">Registro base para la consulta.</param>
        /// <param name="registrosMaximos">Número de registros a recuperar.</param>
        /// <returns></returns>
        public DataTable ListarProductos(int registroBase, int registrosMaximos)
        {
            var dataSet = new DataSet();
            try
            {
                CargarAdapterStoredProcedure("listar_productos");
                miAdapter.Fill(dataSet, registroBase, registrosMaximos, "producto");
                return dataSet.Tables[0];
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar la lista de los productos.\n" + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el total de registros de los productos.
        /// </summary>
        /// <returns></returns>
        public long RowsListarProductos()
        {
            try
            {
                CargarComandoStoredProcedure("count_listar_productos");
                conexion.MiConexion.Open();
                var rows = Convert.ToInt64(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return rows;
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar el total de registros de productos.\n" + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene el listado de la consulta un una coleccion.
        /// </summary>
        /// <param name="codigo">Codigo Interno del Producto a buscar</param>
        /// <returns></returns>
        public DataTable ConsultaPorCodigo(string codigo)
        {
            var tabla = new DataTable();
            try
            {
                CargarAdapterStoredProcedure("listar_productos_codigo");
                miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                miAdapter.Fill(tabla);
                return tabla;
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar la consulta.\n" + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el listado de la consulta un una coleccion. 
        /// </summary>
        /// <param name="nombre">Nombre del Producto a consultar.</param>
        /// <returns>listaproductosnombre</returns>
        public DataTable ConsultaPorNombre(string nombre)
        {
            var tabla = new DataTable();
            try
            {
                CargarAdapterStoredProcedure("consulta_productos_nombre");
                miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                miAdapter.Fill(tabla);
                return tabla;
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar la consulta. " + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el listado de la consulta un una coleccion en base a parte del nombre.
        /// </summary>
        /// <param name="nombre">Nombre o parte de este a consultar.</param>
        /// <param name="registroBase">Registro base para la consulta.</param>
        /// <param name="registrosMaximos">Número de registros a recuperar.</param>
        /// <returns></returns>
        public DataTable FiltroNombre
            (string nombre, int registroBase, int registrosMaximos)
        {
            var dataSet = new DataSet();
            try
            {
                CargarAdapterStoredProcedure("filtro_productos_nombre");
                miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                miAdapter.Fill(dataSet, registroBase, registrosMaximos, "producto");
                return dataSet.Tables[0];
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar la consulta.\n" + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el total de registros de una consulta por nombre de producto.
        /// </summary>
        /// <param name="nombre">Nombre del producto o parte de este.</param>
        /// <returns></returns>
        public long RowsFiltroNombre(string nombre)
        {
            try
            {
                CargarComandoStoredProcedure("count_filtro_productos_nombre");
                comando.Parameters.AddWithValue("nombre", nombre);
                conexion.MiConexion.Open();
                var rows = Convert.ToInt64(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return rows;
            }
            catch (Exception ex)
            {
                throw new Exception
                    ("Ocurrio un error al cargar el total de registros de productos.\n" + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene el listado de productos segun el codigo de la catagoria.
        /// </summary>
        /// <param name="codigo">Codigo de la categoria.</param>
        /// <param name="registroBase">Registro base para la consulta.</param>
        /// <param name="registrosMaximos">Número de registros a recuperar.</param>
        /// <returns></returns>
        public DataTable ConsultaPorCodigoCategoria
            (string codigo, int registroBase, int registrosMaximos)
        {
            var dataSet = new DataSet();
            try
            {
                CargarAdapterStoredProcedure("listar_productos_codigo_categoria");
                miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                miAdapter.Fill(dataSet, registroBase, registrosMaximos, "producto");
                return dataSet.Tables[0];
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar la consulta.\n" + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el total de registros de una consulta de Producto por codigo de categoria.
        /// </summary>
        /// <param name="codigo">Codigo de la categoria.</param>
        /// <returns></returns>
        public long RowsConsultaPorCodigoCategoria(string codigo)
        {
            try
            {
                CargarComandoStoredProcedure
                    ("count_listar_productos_codigo_categoria");
                comando.Parameters.AddWithValue("codigo", codigo);
                conexion.MiConexion.Open();
                var rows = Convert.ToInt64(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return rows;
            }
            catch (Exception ex)
            {
                throw new Exception
                    ("Ocurrio un error al cargar el total de registros de productos.\n" + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene el listado de productos segun el nombre de la categoria.
        /// </summary>
        /// <param name="nombre">Nombre de la categoria o parte de este.</param>
        /// <param name="registroBase">Registro base para la consulta.</param>
        /// <param name="registrosMaximos">Número de registros a recuperar.</param>
        /// <param name="filtro">Indica si es una consulta de filtrado o no.</param>
        /// <returns></returns>
        public DataTable ConsultaPorNombreCategoria
            (string nombre, int registroBase, int registrosMaximos, bool filtro)
        {
            var dataSet = new DataSet();
            try
            {
                if (filtro)
                    CargarAdapterStoredProcedure("filtro_productos_categoria");
                else
                    CargarAdapterStoredProcedure("consulta_productos_categoria");
                miAdapter.SelectCommand.Parameters.AddWithValue("codigo", nombre);
                miAdapter.Fill(dataSet, registroBase, registrosMaximos, "producto");
                return dataSet.Tables[0];
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar la consulta.\n" + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el total de registros de una consulta de Producto por nombre de categoria.
        /// </summary>
        /// <param name="nombre">Nombre de la categoria o parte de este.</param>
        /// <param name="filtro">Indica si es una consulta de filtrado o no.</param>
        /// <returns></returns>
        public long RowsConsultaPorNombreCategoria(string nombre, bool filtro)
        {
            try
            {
                if (filtro)
                    CargarComandoStoredProcedure("count_filtro_productos_categoria");
                else
                    CargarComandoStoredProcedure("count_consulta_productos_categoria");
                comando.Parameters.AddWithValue("nombre", nombre);
                conexion.MiConexion.Open();
                var rows = Convert.ToInt64(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return rows;
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar el total de registros de productos.\n" + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene el listado de productos segun la referencia.
        /// </summary>
        /// <param name="referencia">Referencia o parte de esta a consultar.</param>
        /// <param name="registroBase">Registro base para la consulta.</param>
        /// <param name="registrosMaximos">Número de registros a recuperar.</param>
        /// <param name="color">Indica si la consulta incluye color o no.</param>
        /// <returns></returns>
        public DataTable ConsultaProductoPorReferencia
            (string referencia, int registroBase, int registrosMaximos, bool color)
        {
            var dataSet = new DataSet();
            try
            {
                if (color)
                    CargarAdapterStoredProcedure("productos_combinar_referencia");
                else
                    CargarAdapterStoredProcedure("productos_combinar_referencia_nocolor");
                miAdapter.SelectCommand.Parameters.AddWithValue("referencia", referencia);
                miAdapter.Fill(dataSet, registroBase, registrosMaximos, "producto");
                return dataSet.Tables[0];
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorConsulta + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el total de registros de una consulta de Producto por Referencia.
        /// </summary>
        /// <param name="referencia">Referencia o parte de esta a consultar.</param>
        /// <param name="color">Indica si la consulta incluye color o no.</param>
        /// <returns></returns>
        public long RowsConsultaProductoPorReferencia(string referencia, bool color)
        {
            try
            {
                if (color)
                {
                    CargarComandoStoredProcedure("count_productos_combinar_referencia");
                }
                else
                {
                    CargarComandoStoredProcedure
                        ("count_productos_combinar_referencia_nocolor");
                }
                comando.Parameters.AddWithValue("referencia", referencia);
                conexion.MiConexion.Open();
                var rows = Convert.ToInt64(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return rows;
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorCount + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el listado de productos segun el codigo o el nombre y la referencia.
        /// </summary>
        /// <param name="codigo">Codigo del producto a consultar.</param>
        /// <param name="nombre">Nombre o parte de este del producto a consultar.</param>
        /// <param name="referencia">Referencia o parte de esta a consultar.</param>
        /// <param name="code">Indica si se consulta por Codigo del producto o no.</param>
        /// <param name="color">Indica si la consulta incluye color o no.</param>
        /// <param name="registroBase">Registro base para la consulta.</param>
        /// <param name="registrosMaximos">Número de registros a recuperar.</param>
        /// <returns></returns>
        public DataTable ConsultaProductoConReferencia
            (string codigo, string nombre, string referencia, bool code, bool color,
             int registroBase, int registrosMaximos)
        {
            var dataSet = new DataSet();
            try
            {
                if (code)
                {
                    if (color)
                    {
                        CargarAdapterStoredProcedure("producto_con_referencia_ycolor");
                        miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                        miAdapter.SelectCommand.Parameters.AddWithValue("referencia", referencia);
                    }
                    else
                    {
                        CargarAdapterStoredProcedure("producto_con_referencia");
                        miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                        miAdapter.SelectCommand.Parameters.AddWithValue("referencia", referencia);
                    }
                }
                else
                {
                    if (color)
                    {
                        CargarAdapterStoredProcedure("producto_name_con_referencia_ycolor");
                        miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                        miAdapter.SelectCommand.Parameters.AddWithValue("referencia", referencia);
                    }
                    else
                    {
                        CargarAdapterStoredProcedure("producto_name_con_referencia");
                        miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                        miAdapter.SelectCommand.Parameters.AddWithValue("referencia", referencia);
                    }
                }
                miAdapter.Fill(dataSet, registroBase, registrosMaximos, "producto");
                return dataSet.Tables[0];
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorConsulta + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el total de registros de una consulta segun el codigo o el nombre y la referencia.
        /// </summary>
        /// <param name="codigo">Codigo del producto a consultar.</param>
        /// <param name="nombre">Nombre o parte de este del producto a consultar.</param>
        /// <param name="referencia">Referencia o parte de esta a consultar.</param>
        /// <param name="code">Indica si se consulta por Codigo del producto o no.</param>
        /// <param name="color">Indica si la consulta incluye color o no.</param>
        /// <returns></returns>
        public long RowsConsultaProductoConReferencia
            (string codigo, string nombre, string referencia, bool code, bool color)
        {
            try
            {
                if (code)
                {
                    if (color)
                    {
                        CargarComandoStoredProcedure("count_producto_con_referencia_ycolor");
                        comando.Parameters.AddWithValue("codigo", codigo);
                        comando.Parameters.AddWithValue("referencia", referencia);
                    }
                    else
                    {
                        CargarComandoStoredProcedure("count_producto_con_referencia");
                        comando.Parameters.AddWithValue("codigo", codigo);
                        comando.Parameters.AddWithValue("referencia", referencia);
                    }
                }
                else
                {
                    if (color)
                    {
                        CargarComandoStoredProcedure("count_producto_name_con_referencia_ycolor");
                        comando.Parameters.AddWithValue("nombre", nombre);
                        comando.Parameters.AddWithValue("referencia", referencia);
                    }
                    else
                    {
                        CargarComandoStoredProcedure("count_producto_name_con_referencia");
                        comando.Parameters.AddWithValue("nombre", nombre);
                        comando.Parameters.AddWithValue("referencia", referencia);
                    }
                }
                conexion.MiConexion.Open();
                var rows = Convert.ToInt64(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return rows;
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorCount + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene el listado de productos segun la marca.
        /// </summary>
        /// <param name="codigo">Codigo del producto a consultar.</param>
        /// <param name="nombre">Nombre o parte de este del producto a consultar.</param>
        /// <param name="marca">Marca o parte de esta a consultar.</param>
        /// <param name="talla">Talla o parte de esta a consultar.</param>
        /// <param name="size">Indica si la consulta incluye talla o no.</param>
        /// <param name="product">Indica si la consulta incluye Producto o no.</param>
        /// <param name="code">Indica si se consulta por Codigo del producto o no.</param>
        /// <param name="color">Indica si la consulta incluye color o no.</param>
        /// <param name="registroBase">Registro base para la consulta.</param>
        /// <param name="registrosMaximos">Número de registros a recuperar.</param>
        /// <returns></returns>
        public DataTable ConsultaProductoPorMarca
            (string codigo, string nombre, string marca, string talla, bool size,
             bool product, bool code, bool color, int registroBase, int registrosMaximos)
        {
            var dataSet = new DataSet();
            try
            {
                if (!product)//Marca sola.
                {
                    if (!size && !color)//Consulta marca sin talla y sin color.
                    {
                        CargarAdapterStoredProcedure("productos_marca_nocolor");
                        miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                    }
                    else
                    {
                        if (size && !color)//Consulta marca con talla y sin color
                        {
                            CargarAdapterStoredProcedure("producto_marca_medida");
                            miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                            miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                        }
                        else
                        {
                            if (size && color)//Consulta marca con talla y con color.
                            {
                                CargarAdapterStoredProcedure("producto_marca_medida_ycolor");
                                miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                                miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                            }
                            else//Consulta marca sin talla y con color
                            {
                                CargarAdapterStoredProcedure("productos_marca_ycolor");
                                miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                            }
                        }
                    }
                }
                else //Marca con producto.
                {
                    if (code)//consulta por codigo de producto.
                    {
                        if (!size && !color)//Consulta marca sin talla y sin color.
                        {
                            CargarAdapterStoredProcedure("producto_con_marca_nocolor");
                            miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                            miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                        }
                        else
                        {
                            if (size && !color)//Consulta marca con talla y sin color
                            {
                                CargarAdapterStoredProcedure("producto_code_marca_medida");
                                miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                                miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                                miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                            }
                            else
                            {
                                if (size && color)//Consulta marca con talla y con color.
                                {
                                    CargarAdapterStoredProcedure("producto_code_marca_medida_ycolor");
                                    miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                                    miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                                    miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                                }
                                else//Consulta marca sin talla y con color
                                {
                                    CargarAdapterStoredProcedure("producto_con_marca_ycolor");
                                    miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                                    miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                                }
                            }
                        }
                    }
                    else//consulta por nombre de producto.
                    {
                        if (!size && !color)//Consulta marca sin talla y sin color.
                        {
                            CargarAdapterStoredProcedure("producto_name_con_marca_nocolor");
                            miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                            miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                        }
                        else
                        {
                            if (size && !color)//Consulta marca con talla y sin color
                            {
                                CargarAdapterStoredProcedure("producto_name_marca_medida");
                                miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                                miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                                miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                            }
                            else
                            {
                                if (size && color)//Consulta marca con talla y con color.
                                {
                                    CargarAdapterStoredProcedure("producto_name_marca_medida_ycolor");
                                    miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                                    miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                                    miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                                }
                                else//Consulta marca sin talla y con color
                                {
                                    CargarAdapterStoredProcedure("producto_name_con_marca_ycolor");
                                    miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                                    miAdapter.SelectCommand.Parameters.AddWithValue("marca", marca);
                                }
                            }
                        }
                    }
                }
                miAdapter.Fill(dataSet, registroBase, registrosMaximos, "producto");
                return dataSet.Tables[0];
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorConsulta + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el total de registros de una consulta segun el codigo o el nombre y la marca.
        /// </summary>
        /// <param name="codigo">Codigo del producto a consultar.</param>
        /// <param name="nombre">Nombre o parte de este del producto a consultar.</param>
        /// <param name="marca">Marca o parte de esta a consultar.</param>
        /// <param name="talla">Talla o parte de esta a consultar.</param>
        /// <param name="size">Indica si la consulta incluye talla o no.</param>
        /// <param name="product">Indica si la consulta incluye Producto o no.</param>
        /// <param name="code">Indica si se consulta por Codigo del producto o no.</param>
        /// <param name="color">Indica si la consulta incluye color o no.</param>
        /// <returns></returns>
        public long RowsConsultaProductoPorMarca
            (string codigo, string nombre, string marca, string talla, bool size,
             bool product, bool code, bool color)
        {
            try
            {
                if (!product)//Marca sola.
                {
                    if (!size && !color)//Consulta marca sin talla y sin color.
                    {
                        CargarComandoStoredProcedure("count_productos_marca_nocolor");
                        comando.Parameters.AddWithValue("marca", marca);
                    }
                    else
                    {
                        if (size && !color)//Consulta marca con talla y sin color
                        {
                            CargarComandoStoredProcedure("count_producto_marca_medida");
                            comando.Parameters.AddWithValue("marca", marca);
                            comando.Parameters.AddWithValue("talla", talla);
                        }
                        else
                        {
                            if (size && color)//Consulta marca con talla y con color.
                            {
                                CargarComandoStoredProcedure("count_producto_marca_medida_ycolor");
                                comando.Parameters.AddWithValue("marca", marca);
                                comando.Parameters.AddWithValue("talla", talla);
                            }
                            else//Consulta marca sin talla y con color
                            {
                                CargarComandoStoredProcedure("count_productos_marca_ycolor");
                                comando.Parameters.AddWithValue("marca", marca);
                            }
                        }
                    }
                }
                else //Marca con producto.
                {
                    if (code)//consulta por codigo de producto.
                    {
                        if (!size && !color)//Consulta marca sin talla y sin color.
                        {
                            CargarComandoStoredProcedure("count_producto_con_marca_nocolor");
                            comando.Parameters.AddWithValue("codigo", codigo);
                            comando.Parameters.AddWithValue("marca", marca);
                        }
                        else
                        {
                            if (size && !color)//Consulta marca con talla y sin color
                            {
                                CargarComandoStoredProcedure("count_producto_code_marca_medida");
                                comando.Parameters.AddWithValue("codigo", codigo);
                                comando.Parameters.AddWithValue("marca", marca);
                                comando.Parameters.AddWithValue("talla", talla);
                            }
                            else
                            {
                                if (size && color)//Consulta marca con talla y con color.
                                {
                                    CargarComandoStoredProcedure("count_producto_code_marca_medida_ycolor");
                                    comando.Parameters.AddWithValue("codigo", codigo);
                                    comando.Parameters.AddWithValue("marca", marca);
                                    comando.Parameters.AddWithValue("talla", talla);
                                }
                                else//Consulta marca sin talla y con color
                                {
                                    CargarComandoStoredProcedure("count_producto_con_marca_ycolor");
                                    comando.Parameters.AddWithValue("codigo", codigo);
                                    comando.Parameters.AddWithValue("marca", marca);
                                }
                            }
                        }
                    }
                    else//consulta por nombre de producto.
                    {
                        if (!size && !color)//Consulta marca sin talla y sin color.
                        {
                            CargarComandoStoredProcedure("count_producto_name_con_marca_nocolor");
                            comando.Parameters.AddWithValue("nombre", nombre);
                            comando.Parameters.AddWithValue("marca", marca);
                        }
                        else
                        {
                            if (size && !color)//Consulta marca con talla y sin color
                            {
                                CargarComandoStoredProcedure("count_producto_name_marca_medida");
                                comando.Parameters.AddWithValue("nombre", nombre);
                                comando.Parameters.AddWithValue("marca", marca);
                                comando.Parameters.AddWithValue("talla", talla);
                            }
                            else
                            {
                                if (size && color)//Consulta marca con talla y con color.
                                {
                                    CargarComandoStoredProcedure("count_producto_name_marca_medida_ycolor");
                                    comando.Parameters.AddWithValue("nombre", nombre);
                                    comando.Parameters.AddWithValue("marca", marca);
                                    comando.Parameters.AddWithValue("talla", talla);
                                }
                                else//Consulta marca sin talla y con color
                                {
                                    CargarComandoStoredProcedure("count_producto_name_con_marca_ycolor");
                                    comando.Parameters.AddWithValue("nombre", nombre);
                                    comando.Parameters.AddWithValue("marca", marca);
                                }
                            }
                        }
                    }
                }
                conexion.MiConexion.Open();
                var rows = Convert.ToInt64(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return rows;
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorCount + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene el listado de productos segun la talla.
        /// </summary>
        /// <param name="codigo">Codigo del producto a consultar.</param>
        /// <param name="nombre">Nombre o parte de este del producto a consultar.</param>
        /// <param name="talla">Talla o parte de esta a consultar.</param>
        /// <param name="product">Indica si la consulta incluye Producto o no.</param>
        /// <param name="code">Indica si se consulta por Codigo del producto o no.</param>
        /// <param name="color">Indica si la consulta incluye color o no.</param>
        /// <param name="registroBase">Registro base para la consulta.</param>
        /// <param name="registrosMaximos">Número de registros a recuperar.</param>
        /// <returns></returns>
        public DataTable ConsultaProductoPorTalla(string codigo, string nombre, string talla,
            bool product, bool code, bool color, int registroBase, int registrosMaximos)
        {
            var dataSet = new DataSet();
            try
            {
                if (product)
                {
                    if (code)
                    {
                        if (color)
                        {
                            CargarAdapterStoredProcedure("producto_con_medida_ycolor");
                            miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                            miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                        }
                        else
                        {
                            CargarAdapterStoredProcedure("producto_con_medida");
                            miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                            miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                        }
                    }
                    else
                    {
                        if (color)
                        {
                            CargarAdapterStoredProcedure("producto_name_con_medida_ycolor");
                            miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                            miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                        }
                        else
                        {
                            CargarAdapterStoredProcedure("producto_name_con_medida");
                            miAdapter.SelectCommand.Parameters.AddWithValue("nombre", nombre);
                            miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                        }
                    }
                }
                else//talla sola
                {
                    if (color)//con color
                    {
                        CargarAdapterStoredProcedure("producto_medida_ycolor");
                        miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                    }
                    else//sin color
                    {
                        CargarAdapterStoredProcedure("producto_medida");
                        miAdapter.SelectCommand.Parameters.AddWithValue("talla", talla);
                    }
                }
                miAdapter.Fill(dataSet, registroBase, registrosMaximos, "producto");
                return dataSet.Tables[0];
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorConsulta + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el total de registros de una consulta segun el codigo o el nombre y la talla.
        /// </summary>
        /// <param name="codigo">Codigo del producto a consultar.</param>
        /// <param name="nombre">Nombre o parte de este del producto a consultar.</param>
        /// <param name="talla">Talla o parte de esta a consultar.</param>
        /// <param name="product">Indica si la consulta incluye Producto o no.</param>
        /// <param name="code">Indica si se consulta por Codigo del producto o no.</param>
        /// <param name="color">Indica si la consulta incluye color o no.</param>
        /// <returns></returns>
        public long RowsConsultaProductoPorTalla(string codigo, string nombre, string talla,
            bool product, bool code, bool color)
        {
            try
            {
                if (product)
                {
                    if (code)
                    {
                        if (color)
                        {
                            CargarComandoStoredProcedure("count_producto_con_medida_ycolor");
                            comando.Parameters.AddWithValue("codigo", codigo);
                            comando.Parameters.AddWithValue("talla", talla);
                        }
                        else
                        {
                            CargarComandoStoredProcedure("count_producto_con_medida");
                            comando.Parameters.AddWithValue("codigo", codigo);
                            comando.Parameters.AddWithValue("talla", talla);
                        }
                    }
                    else
                    {
                        if (color)
                        {
                            CargarComandoStoredProcedure("count_producto_name_con_medida_ycolor");
                            comando.Parameters.AddWithValue("nombre", nombre);
                            comando.Parameters.AddWithValue("talla", talla);
                        }
                        else
                        {
                            CargarComandoStoredProcedure("count_producto_name_con_medida");
                            comando.Parameters.AddWithValue("nombre", nombre);
                            comando.Parameters.AddWithValue("talla", talla);
                        }
                    }
                }
                else//talla sola
                {
                    if (color)//con color
                    {
                        CargarComandoStoredProcedure("count_producto_medida_ycolor");
                        comando.Parameters.AddWithValue("talla", talla);
                    }
                    else//sin color
                    {
                        CargarComandoStoredProcedure("count_producto_medida");
                        comando.Parameters.AddWithValue("talla", talla);
                    }
                }
                conexion.MiConexion.Open();
                var rows = Convert.ToInt64(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return rows;
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorCount + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene el registro completo de los datos de un Producto.
        /// </summary>
        /// <param name="codigo">Codigo Interno del producto a consultar.</param>
        /// <returns></returns>
        public Producto ProductoCompleto(string codigo)
        {
            var producto = new Producto();
            var descuento = new DaoDescuento();
            var recargo = new DaoRecargo();
            try
            {
                CargarComandoStoredProcedure("consulta_producto_completo");
                comando.Parameters.AddWithValue("codigo", codigo);
                conexion.MiConexion.Open();
                NpgsqlDataReader miReader = comando.ExecuteReader();
                while (miReader.Read())
                {
                    producto.CodigoInternoProducto = miReader.GetString(0);
                    producto.CodigoBarrasProducto = miReader.GetString(1);
                    producto.ReferenciaProducto = miReader.GetString(2);
                    producto.NombreProducto = miReader.GetString(3);
                    producto.DescripcionProducto = miReader.GetString(4);
                    producto.CodigoCategoria = miReader.GetString(5);
                    producto.NombreCategoria = miReader.GetString(6);
                    producto.IdMarca = miReader.GetInt32(7);
                    producto.NombreMarca = miReader.GetString(8);
                    producto.UtilidadPorcentualProducto = miReader.GetDouble(9);
                    producto.ValorVentaProducto = miReader.GetInt32(10);
                    producto.AplicaPrecioPorcentaje = miReader.GetBoolean(11);
                    producto.IdIva = miReader.GetInt32(12);
                    producto.ValorIva = miReader.GetDouble(13);
                    producto.UnidadVentaProducto = miReader.GetInt32(14);
                    producto.CantidadMinimaProducto = miReader.GetInt32(15);
                    producto.CantidadMaximaProducto = miReader.GetInt32(16);
                    producto.EstadoProducto = miReader.GetBoolean(17);
                    producto.AplicaTalla = miReader.GetBoolean(18);
                    producto.AplicaColor = miReader.GetBoolean(19);
                    producto.CantidadDecimal = miReader.GetBoolean(20);
                }
                conexion.MiConexion.Close();
                comando.Dispose();
                producto.Descuentos = descuento.ListadoDeDescuento(codigo);
                producto.Recargos = recargo.ListadoDeRecargo(codigo);
                return producto;
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar los datos del Producto.\n" + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene ul listado de los registros de medida de los productos.
        /// </summary>
        /// <param name="codigo">Codigo del producto a consultar.</param>
        /// <returns></returns>
        public DataTable ProductoConMedida(string codigo)
        {
            var tabla = new DataTable();
            try
            {
                CargarAdapterStoredProcedure("producto_con_medida");
                miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                miAdapter.Fill(tabla);
                return tabla;
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar la(s) medida(s) del Producto.\n" + ex.Message);
            }
        }

        /// <summary>
        /// Obtiene el listado de colores de un producto segun su medida.
        /// </summary>
        /// <param name="codigo">Codigo del producto a consultar.</param>
        /// <param name="idMedida">Id de la medida del Producto.</param>
        /// <returns></returns>
        public DataTable ProductoConMedidaYcolor(string codigo, int idMedida)
        {
            var table = new DataTable();
            try
            {
                CargarAdapterStoredProcedure("color_producto_con_medida");
                miAdapter.SelectCommand.Parameters.AddWithValue("codigo", codigo);
                miAdapter.SelectCommand.Parameters.AddWithValue("medida", idMedida);
                miAdapter.Fill(table);
                return table;
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al cargar los colores del Producto.\n" + ex.Message);
            }
        }


        //

        /// <summary>
        /// Obtiene el último valor ingresado en factura de un Producto
        /// </summary>
        /// <param name="inventario">Inventario del producto a consultar.</param>
        /// <returns></returns>
        public int UltimoValorProducto(Inventario inventario)
        {
            try
            {
                CargarComandoStoredProcedure(ultimoValor);
                comando.Parameters.AddWithValue("codigo", inventario.CodigoProducto);
                comando.Parameters.AddWithValue("medida", inventario.IdMedida);
                comando.Parameters.AddWithValue("color", inventario.IdColor);
                conexion.MiConexion.Open();
                var valor = Convert.ToInt32(comando.ExecuteScalar());
                conexion.MiConexion.Close();
                comando.Dispose();
                return valor;
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorUltimoPrecio + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene un promedio de los valores de Producto segun facturas de proveedor.
        /// </summary>
        /// <param name="inventario">Inventario de Producto a consultar.</param>
        /// <returns></returns>
        public int PromedioValorProducto(Inventario inventario)
        {
            int promedio = 0;
            try
            {
                CargarComandoStoredProcedure(UltimosValores);
                comando.Parameters.AddWithValue("codigo", inventario.CodigoProducto);
                comando.Parameters.AddWithValue("medida", inventario.IdMedida);
                comando.Parameters.AddWithValue("color", inventario.IdColor);
                comando.Parameters.AddWithValue("limite", inventario.Cantidad);
                conexion.MiConexion.Open();
                NpgsqlDataReader miReader = comando.ExecuteReader();
                var contador = 0;
                while (miReader.Read())
                {
                    promedio += miReader.GetInt32(0);
                    contador++;
                }
                promedio = promedio / contador;
                conexion.MiConexion.Close();
                comando.Dispose();
                return promedio;
            }
            catch (Exception ex)
            {
                throw new Exception(ErrorUltimoPrecio + ex.Message);
            }
            finally 
            { 
                conexion.MiConexion.Close();
                promedio = 0;
            }
        }

        /// <summary>
        /// Edita los datos de un registro de Producto.
        /// </summary>
        /// <param name="producto">Producto a editar.</param>
        public void EditarProducto(Producto producto)
        {
            var daoDescuento = new DaoDescuento();
            var daoRecargo = new DaoRecargo();
            try
            {
                CargarComandoStoredProcedure("editar_producto");
                comando.Parameters.AddWithValue("codigoo", producto.CodigoInternoProducto);
                comando.Parameters.AddWithValue("codigoEditado", producto.CodigoInternoEditado);
                comando.Parameters.AddWithValue("barras", producto.CodigoBarrasProducto);
                comando.Parameters.AddWithValue("referencia", producto.ReferenciaProducto);
                comando.Parameters.AddWithValue("nombre", producto.NombreProducto);
                comando.Parameters.AddWithValue("descripcion", producto.DescripcionProducto);
                comando.Parameters.AddWithValue("categoria", producto.CodigoCategoria);
                comando.Parameters.AddWithValue("idMarca", producto.IdMarca);
                comando.Parameters.AddWithValue("utilidad", producto.UtilidadPorcentualProducto);
                comando.Parameters.AddWithValue("valor", producto.ValorVentaProducto);
                comando.Parameters.AddWithValue("aplicaPorcentaje", producto.AplicaPrecioPorcentaje);
                comando.Parameters.AddWithValue("idIva", producto.IdIva);
                comando.Parameters.AddWithValue("unidadVenta", producto.UnidadVentaProducto);
                comando.Parameters.AddWithValue("minima", producto.CantidadMinimaProducto);
                comando.Parameters.AddWithValue("maxima", producto.CantidadMaximaProducto);
                comando.Parameters.AddWithValue("estado", producto.EstadoProducto);
                comando.Parameters.AddWithValue("talla", producto.AplicaTalla);
                comando.Parameters.AddWithValue("color", producto.AplicaColor);
                comando.Parameters.AddWithValue("cantdecimal", producto.CantidadDecimal);
                conexion.MiConexion.Open();
                comando.ExecuteNonQuery();
                conexion.MiConexion.Close();
                comando.Dispose();
                var descuentos = daoDescuento.ListadoDeDescuento(producto.CodigoInternoEditado);
                var recargos = daoRecargo.ListadoDeRecargo(producto.CodigoInternoEditado);
                ///Elimina relaciones de Descuento y Recargo que ya no existen.
                foreach (Descuento d in descuentos)
                {
                    var noExiste = true;
                    foreach (Descuento d1 in producto.Descuentos)
                    {
                        if (d.IdDescuento == d1.IdDescuento)
                        {
                            noExiste = false;
                            break;
                        }
                        else
                        {
                            noExiste = true;
                        }
                    }
                    if (noExiste)
                    {
                        daoDescuento.EliminarDescuento(d.IdDescuento, producto.CodigoInternoEditado);
                    }
                }
                foreach (Recargo r in recargos)
                {
                    var noExiste = true;
                    foreach (Recargo r1 in producto.Recargos)
                    {
                        if (r.IdRecargo == r1.IdRecargo)
                        {
                            noExiste = false;
                            break;
                        }
                        else
                        {
                            noExiste = true;
                        }
                    }
                    if (noExiste)
                    {
                        daoRecargo.EliminarRecargo(r.IdRecargo, producto.CodigoInternoEditado);
                    }
                }

                ///Ingresa relaciones de Descuento y Recargo que ha sido añadidas.
                foreach (Descuento des in producto.Descuentos)
                {
                    var existe = true;
                    foreach (Descuento des1 in descuentos)
                    {
                        if (des.IdDescuento == des1.IdDescuento)
                        {
                            existe = false;
                            break;
                        }
                        else
                        {
                            existe = true;
                        }
                    }
                    if (existe)
                    {
                        des.CodigoInternoProducto = producto.CodigoInternoEditado;
                        daoDescuento.InsertarDescuento(des);
                    }
                }
                foreach (Recargo rec in producto.Recargos)
                {
                    var existe = true;
                    foreach (Recargo rec1 in recargos)
                    {
                        if (rec.IdRecargo == rec1.IdRecargo)
                        {
                            existe = false;
                            break;
                        }
                        else
                        {
                            existe = true;
                        }
                    }
                    if (existe)
                    {
                        rec.CodigoInternoProducto = producto.CodigoInternoEditado;
                        daoRecargo.InsertarRecargo(rec);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un error al editar los datos del Producto.\n" + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Elimina el registro de Producto de la base de datos.
        /// </summary>
        /// <param name="codigo">Codigo Interno del Producto a eliminar.</param>
        public void EliminarProducto(string codigo)
        {
            try
            {
                CargarComandoStoredProcedure("eliminar_producto");
                comando.Parameters.AddWithValue("codigo", codigo);
                conexion.MiConexion.Open();
                comando.ExecuteNonQuery();
                conexion.MiConexion.Close();
                comando.Dispose();
            }
            catch (Exception)
            {
                throw new Exception("No se puede eliminar el Producto porque aun se encuentra en Inventario.");
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene los datos basicos de un producto.
        /// </summary>
        /// <param name="codigo">Codigo a consultar.</param>
        /// <returns></returns>
        public ArrayList ProductoBasico(string codigo)
        {
            ArrayList lista = new ArrayList();
            ValorUnidadMedida lista1 = new ValorUnidadMedida();
            try
            {
                CargarComandoStoredProcedure("producto_basico");
                comando.Parameters.AddWithValue("codigo", codigo);
                Producto producto = new Producto();
                conexion.MiConexion.Open();
                NpgsqlDataReader miReader = comando.ExecuteReader();
                while (miReader.Read())
                {
                    producto = new Producto();
                    producto.CodigoInternoProducto = miReader.GetString(0);
                    producto.CodigoBarrasProducto = miReader.GetString(1);
                    producto.NombreProducto = miReader.GetString(2);
                    producto.NombreMarca = miReader.GetString(3);
                    producto.AplicaTalla = miReader.GetBoolean(4);
                    producto.AplicaColor = miReader.GetBoolean(5);
                    producto.ValorIva = miReader.GetDouble(7);
                    producto.AplicaPrecioPorcentaje = miReader.GetBoolean(8);
                    producto.ValorVentaProducto = miReader.GetInt32(9);
                    producto.UtilidadPorcentualProducto = miReader.GetDouble(10);
                    producto.CantidadDecimal = miReader.GetBoolean(11);
                    lista.Add(producto);
                }
                conexion.MiConexion.Close();
                comando.Dispose();
                if (!producto.AplicaTalla)
                {
                    lista1 = ProductoMedida(producto.CodigoInternoProducto);
                    lista.Add(lista1);
                }
                return lista;
            }
            catch (Exception ex)
            {
                throw new Exception("Ocurrio un Error al cargar el Producto\n" + ex.Message);
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Obtiene la unidad de medida del Producto.
        /// </summary>
        /// <param name="codigo">Codigo del Producto a consultar.</param>
        /// <returns></returns>
        private ValorUnidadMedida ProductoMedida(string codigo)
        {
            ValorUnidadMedida medida = new ValorUnidadMedida();
            try
            {
                CargarComandoStoredProcedure("producto_medida_codigo");
                comando.Parameters.AddWithValue("codigo", codigo);
                conexion.MiConexion.Open();
                NpgsqlDataReader miReader = comando.ExecuteReader();
                while (miReader.Read())
                {
                    medida.DescripcionUnidadMedida = miReader.GetString(1);
                    medida.IdValorUnidadMedida = miReader.GetInt32(2);
                    medida.DescripcionValorUnidadMedida = miReader.GetString(3);
                }
                conexion.MiConexion.Close();
                comando.Dispose();
                return medida;
            }
            catch (Exception)
            {
                throw new Exception();
            }
            finally { conexion.MiConexion.Close(); }
        }

        /// <summary>
        /// Carga y relaciona producto a sorteo.
        /// </summary>
        /// <param name="idSorteo"></param>
        /// <param name="codigoInternoProducto"></param>
        public void InsertarProductoSorteo(int idSorteo, string codigoInternoProducto, bool historial)
        {
            try
            {
                if (historial)
                {
                    CargarComandoStoredProcedure("insertar_historial_sorteo_producto");
                }
                else
                {
                    CargarComandoStoredProcedure("insertar_sorteo_producto");
                }
                comando.Parameters.AddWithValue("idSorteo", idSorteo);
                comando.Parameters.AddWithValue("codigoInternoProducto",codigoInternoProducto);
                conexion.MiConexion.Open();
                comando.ExecuteNonQuery();
                conexion.MiConexion.Close();
                comando.Dispose();
            }
            catch(Exception ex) 
            {
                throw new Exception("Error al insertar el producto" + ex.Message);
            }
            finally 
            {
                conexion.MiConexion.Close();
            }
        }

        /// <summary>
        /// Consulta producto por codigo interno y por codigo de barras
        /// </summary>
        /// <param name="codigo"></param>
        /// <returns></returns>
          public Producto ConsultaProductoSimple(string codigo)
          {
              try
              {
                  CargarComandoStoredProcedure("consulta_producto_simple");
                  comando.Parameters.AddWithValue("codigoproducto", codigo);
                  conexion.MiConexion.Open();
                  NpgsqlDataReader reader = comando.ExecuteReader();
                  var producto = new Producto();
                  while (reader.Read())
                  {
                      producto.CodigoInternoProducto = reader.GetString(0);
                      producto.NombreProducto = reader.GetString(1);                      
                  }
                  conexion.MiConexion.Close();
                  comando.Dispose();

                  return producto;
              }
              catch (Exception ex)
              {
                  throw new Exception("Error al consultar los productos" + ex.Message);
              }
              finally
              {
                  conexion.MiConexion.Close();
              }
          }

        /// <summary>
        /// Listo categorias de sorteo.
        /// </summary>
        /// <param name="idsorteo"></param>
        /// <returns></returns>
          public List<Producto> CargaProductoSorteo(int idsorteo ,bool historial)
          {
              List<Producto> ListaProductoSarteo = new List<Producto>();
              try
              {
                  if (historial)
                  {
                      CargarComandoStoredProcedure("historial_sorteo_producto");
                  }
                  else
                  {
                      CargarComandoStoredProcedure("sorteo_producto");
                  }
                  comando.Parameters.AddWithValue("idSorteo", idsorteo);
                  conexion.MiConexion.Open();
                  NpgsqlDataReader myreader = comando.ExecuteReader();
                  while (myreader.Read())
                  {
                      Producto miproducto = new Producto();
                      miproducto.CodigoInternoProducto = myreader.GetString(0);
                      miproducto.NombreProducto = myreader.GetString(3);
                      ListaProductoSarteo.Add(miproducto);
                  }
                  conexion.MiConexion.Close();               
                  comando.Dispose();
                  return ListaProductoSarteo;
              }
              catch(Exception ex)
              {
                  throw new Exception("No se pudo listar las categorias" + ex.Message);
              }
              finally
              {
                  conexion.MiConexion.Close();
              }
          }

        /// <summary>
        /// insertar producto a promocion.
        /// </summary>
        /// <param name="idPromocion"></param>
        /// <param name="codigoInternoproducto"></param>
        /// <param name="cantidadProducto"></param>
          public void InsertarProductoPromocion(int idPromocion, string codigoInternoproducto, int cantidadProducto)
          {
              try
              {
                  CargarComandoStoredProcedure("insertar_promocion_producto");
                  comando.Parameters.AddWithValue("idpromocion", idPromocion);
                  comando.Parameters.AddWithValue("codigoInternoProducto", codigoInternoproducto);
                  comando.Parameters.AddWithValue("cantidadpruducto", cantidadProducto);
                  conexion.MiConexion.Open();
                  comando.ExecuteNonQuery();
                  conexion.MiConexion.Close();
                  comando.Dispose();
              }
              catch(Exception ex)
              {
                  throw new Exception("Error al insertar producto a promocion" + ex.Message);
              }
              finally
              {
                  conexion.MiConexion.Close();
              }
          }

        /// <summary>
        /// Edita producto de promocion
        /// </summary>
        /// <param name="idPromocion">id promocion</param>
        /// <param name="codigoInternoproducto">codigoInternnoproducto</param>
        /// <param name="cantidadProducto">cantidad</param>
        public void EditarProductoPromocion(int idPromocion, string codigoInternoproducto, int cantidadProducto)
        {
            try
            {
                CargarComandoStoredProcedure("edita_promocion_Producto");
                comando.Parameters.AddWithValue("idpromocion", idPromocion);
                comando.Parameters.AddWithValue("codigoproducto", codigoInternoproducto);
                comando.Parameters.AddWithValue("cantidad", cantidadProducto);
                conexion.MiConexion.Open();
                comando.ExecuteNonQuery();
                conexion.MiConexion.Close();
                comando.Dispose();
            }
            catch(Exception ex)
            {
                throw new Exception("Error al editar el producto" + ex.Message);
            }
            finally
            {
                conexion.MiConexion.Close();
            }
        }

        /// <summary>
        /// Inicializa una nueva instancia de NpgsqlCommand de tipo Stored Procedure.
        /// </summary>
        /// <param name="cmd">Sentencia a ejecutar.</param>
        private void CargarComandoStoredProcedure(string cmd)
        {
            comando = new NpgsqlCommand();
            comando.Connection = conexion.MiConexion;
            comando.CommandType = System.Data.CommandType.StoredProcedure;
            comando.CommandText = cmd;
        }

        /// <summary>
        /// Inicializa una nueva instancia de NpgsqlDataAdapter de tipo Stored Procedure.
        /// </summary>
        /// <param name="cmd">Sentencia a ejecutar.</param>
        private void CargarAdapterStoredProcedure(string cmd)
        {
            miAdapter = new NpgsqlDataAdapter(cmd, conexion.MiConexion);
            miAdapter.SelectCommand.CommandType = System.Data.CommandType.StoredProcedure;
        }

        #endregion
    }
}